/**
 * 
 */
package adnotatio.rdf;

/**
 * This is a common super-class for value wrappers; instances of this type are
 * used to store values of resource properties. There are three value types:
 * <ul>
 * <li>{@link Literal} - it is a wrapper for all literal values (strings,
 * integers, plain java objects...)</li>
 * <li>{@link Reference} - it is a reference to an another resource </li>
 * <li> {@link Container} - it is used to store multiple values where each value
 * is an instance of the {@link PropertyValue}</li>
 * </ul>
 * 
 * @author kotelnikov
 */
public abstract class PropertyValue extends Entity {

    /**
     * Interprets the given object as an identifier ({@link ID}). If the given
     * object is an identifier already then this method just casts down and
     * returns the given object. If the value is a resource ({@link Resource})
     * or a reference to an resource ({@link Reference}) then this method
     * extracts and returns the corresponding resource identifier. Otherwise
     * this method transforms the given object to a string ({@link Object#toString()})
     * and creates a new id using this value.
     * 
     * @param value the value to transform to an identifier
     * @return an identifier corresponding to the given object
     */
    public static ID toID(Object value) {
        if (value == null)
            return null;
        if (value instanceof ID)
            return (ID) value;
        if (value instanceof Resource)
            return ((Resource) value).getID();
        if (value instanceof Reference)
            return ((Reference) value).getID();
        String str = value.toString();
        return new ID(str);
    }

    /**
     * @param model
     */
    protected PropertyValue(Model model) {
        super(model);
    }

    /**
     * @param visitor
     */
    public abstract void accept(IValueVisitor visitor);

    /**
     * Wraps (if neccessery) this value in a container and returns this
     * resulting container.
     * 
     * @return a container containing this value
     */
    public Container getAsContainer() {
        if (this instanceof Container) {
            return (Container) this;
        } else {
            Container container = fModel.newContainer();
            container.add(this);
            return container;
        }
    }

    /**
     * Returns the value corresponding to this value wrapper
     * 
     * @return the value corresponding to this value wrapper
     */
    public abstract Object getValue();

}
